// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Jeff Stewart
//
// Windows specializations for localhost probe.

#include <windows.h>
#include <winnls.h>

#include "probes/localhost.h"

namespace {

QString WCharToQString(const WCHAR *in) {
  QString rval;
  if (!in) {
    return rval;
  }
  while (*in) {
    rval.push_back(QChar(*in++));
  }
  return rval;
}

}  // anonymous namespace

namespace popdiag {

// retrieve the offset to be applied to GMT to get local time.
// return MAX_INT if you cannot determine it
int LocalHostProbe::GetOffsetFromGMTInMinutes() {
  TIME_ZONE_INFORMATION tzinfo = { 0 };
  DWORD tznow = GetTimeZoneInformation(&tzinfo);
  // GetTimeZoneInformation returns offset from local to GMT.
  // invert it:
  return -tzinfo.Bias;
}

QString LocalHostProbe::GetTimezoneName() {
  TIME_ZONE_INFORMATION tzinfo = { 0 };
  DWORD tznow = GetTimeZoneInformation(&tzinfo);
  if (tznow == TIME_ZONE_ID_UNKNOWN) {
    return "Unknown";
  }
  QString rval;
  bool is_dst = (tznow == TIME_ZONE_ID_DAYLIGHT);
  if (is_dst) {
    rval = WCharToQString(tzinfo.DaylightName);
  } else {
    rval = WCharToQString(tzinfo.StandardName);
  }
  return rval;
}

void LocalHostProbe::LogLocale() {
  TCHAR data[256];

  const int kEnglishCountryName = 0x1002;
  if (0 != GetLocaleInfo(LOCALE_USER_DEFAULT, kEnglishCountryName,
                         data, sizeof(data))) {
    LogDetails("Country", true, WCharToQString(data));
  } else {
    LogDetails("Country", false, "Cannot determine");
  }

  // ISO 3166 country name:
  const int kAbbreviatedCountryName = 0x05A;
  if (0 != GetLocaleInfo(LOCALE_USER_DEFAULT, kAbbreviatedCountryName,
                         data, sizeof(data))) {
    LogDetails("Country Code", true, WCharToQString(data));
  } else {
    LogDetails("Country Code", false, "Cannot determine");
  }

  // ISO 639 language code:
  const int kTwoLetterLanguageCode = 0x059;
  if (0 != GetLocaleInfo(LOCALE_USER_DEFAULT, kTwoLetterLanguageCode,
                         data, sizeof(data))) {
    LogDetails("UI Language", true, WCharToQString(data));
  } else {
    LogDetails("UI Language", false, "Cannot determine");
  }
}

void LocalHostProbe::LogOSVersion() {
  OSVERSIONINFOEX verinfo = { 0 };
  verinfo.dwOSVersionInfoSize = sizeof(verinfo);
  // silly API can take one of several types, but of course
  // C APIs aren't polymorphic.  You're just supposed to cast it :(.
  GetVersionEx(reinterpret_cast<LPOSVERSIONINFOW>(&verinfo));
  DWORD verMajor = verinfo.dwMajorVersion;
  DWORD verMinor = verinfo.dwMinorVersion;
  QString os = "??";
  switch (verMajor) {
    case 4:
      os = "NT4.0";
      break;
    case 5:
      switch (verMinor) {
        case 0:
          os = "Win2K";
          break;
        case 1:
          os = "WinXP";
          break;
        case 2:
          os = "Server2003";
          break;
        default:
          os = QString("unknown%1.%2").arg(verMajor).arg(verMinor);
      }
      break;
    case 6:
      os = "Vista";
      break;
  }
  if (verinfo.wSuiteMask & VER_SUITE_PERSONAL) {
    os += " Home";
  }
  if (verinfo.wSuiteMask & VER_SUITE_EMBEDDEDNT) {
    os += " Embedded";
  }
  // not defined in the 7.1 platform SDK
  const int kSmTabletPc = 86;
  if (GetSystemMetrics(kSmTabletPc)) {
    os += " Tablet";
  }

  os += QString(" SP %1.%2").arg(verinfo.wServicePackMajor)
                            .arg(verinfo.wServicePackMinor);
  os += QString(" Build %1").arg(verinfo.dwBuildNumber);
  LogDetails("Operating System", true, os);

  if (GetSystemMetrics(SM_NETWORK) & 0x01) {
    LogDetails("Network", true, "Present");
  } else {
    LogDetails("Network", false, "Missing");
  }
}

}  // namespace popdiag
